package com.example.hackotontest;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import com.example.hackotontest.dto.UserStoryDto;

import jxl.Cell;
import jxl.Sheet;
import jxl.Workbook;
import jxl.read.biff.BiffException;
import android.app.ListActivity;
import android.content.Intent;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Handler;
import android.text.format.Formatter;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;

public class USListActivity extends ListActivity {

	// how many to load on reaching the bottom
	int itemsPerPage = 15;
	boolean loadingMore = false;

	ArrayList<String> usItems;
	ArrayAdapter<String> adapter;

	Calendar d = Calendar.getInstance();
	TextView textView;

	final File file = new File("/sdcard/hackaton/", "USList.xls");
	Workbook workbook;

	// communication server fields
	public static String ScrumMasterIP = "10.0.2.15";
	public static final int SERVERPORT = 8080;
	private Handler handler = new Handler();
	private ServerSocket serverSocket;

	private final Map<Integer, Socket> salahorPorts = new HashMap<Integer, Socket>();
	private static int connectedSalahors = 0;
	private String username;

	// fields related to sending messages to salahors.
	private String salahorIpAddress = "10.0.2.2";
	private TextView textMessages;
	private String messagesFromSalahors;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_uslist);

		textView = (TextView) findViewById(R.id.serverip);
		textMessages = (TextView) findViewById(R.id.message_from_salahors);

		// get the username
		Intent intent = getIntent();
		String username = intent.getStringExtra("username");

		usItems = new ArrayList<String>();
		adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, usItems);

		readFile();

		this.setListAdapter(adapter);

		textView.setText(getLocalIpAddress());
		System.out.println("------------------------my ip:" + getLocalIpAddress());

		registerItemListener();

		// start server
		Thread fst = new Thread(new ScrumMasterServerThread());
		fst.start();
	}

	public List<String> readFile() {
		List<String> userStories = new ArrayList<String>();

		try {
			workbook = Workbook.getWorkbook(file);

			Sheet sheet = workbook.getSheet("Sheet1");
			int rowNr = sheet.getRows();
			System.out.println("--------------------ROWS found:" + rowNr);

			for (int i = 0; i < rowNr; i++) {
				if (sheet.getCell(0, i) != null) {
					Cell a1 = sheet.getCell(0, i);
					String str = a1.getContents();
					adapter.add(str);
				}
			}
		} catch (BiffException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return userStories;
	}

	public String getLocalIpAddress() {
		WifiManager wim = (WifiManager) getSystemService(WIFI_SERVICE);
		List<WifiConfiguration> l = wim.getConfiguredNetworks();
		if (l.size() > 0) {
			WifiConfiguration wc = l.get(0);
			System.out.println("\n" + Formatter.formatIpAddress(wim.getConnectionInfo().getIpAddress()));
		}
		return Formatter.formatIpAddress(wim.getConnectionInfo().getIpAddress()) != null ? Formatter.formatIpAddress(wim.getConnectionInfo().getIpAddress()) : "NO CONNECTION AVAILABLE";
	}

	/**
	 * Thread responsible to listen to Participant messages
	 * 
	 * @author parvu georgian
	 * 
	 */
	public class ScrumMasterServerThread implements Runnable {

		public void run() {
			try {
				if (ScrumMasterIP != null) {
					handler.post(new Runnable() {
						@Override
						public void run() {
							textView.setText("Listening on IP: " + ScrumMasterIP);
						}
					});
					serverSocket = new ServerSocket(SERVERPORT);
					while (true) {
						// listen for incoming clients
						Socket client = serverSocket.accept();
						handler.post(new Runnable() {
							@Override
							public void run() {
								textView.setText("Connected.");
							}
						});

						handleSalahorMessages(client);
					}
				} else {
					handler.post(new Runnable() {
						@Override
						public void run() {
							textView.setText("Couldn't detect internet connection.");
						}
					});
				}
			} catch (Exception e) {
				handler.post(new Runnable() {
					@Override
					public void run() {
						textView.setText("Error");
					}
				});
				e.printStackTrace();
			}
		}

		private void handleSalahorMessages(Socket client) {
			Thread shj = new Thread(new SalahorHandlerJob(client));
			shj.start();
		}
	}

	/**
	 * Class used to handle each salahor connection on a separate thread.
	 * 
	 * @author parvu georgian
	 * 
	 */
	public class SalahorHandlerJob implements Runnable {

		private Socket client;

		public SalahorHandlerJob(Socket client) {
			super();
			this.client = client;
			connectedSalahors++;
		}

		@Override
		public void run() {
			try {
				// ObjectInputStream objectInputStream = new ObjectInputStream(client.getInputStream());
				// UserStoryDto userStoryDto = (UserStoryDto) objectInputStream.readObject();
				// Log.d("User story text received: ", userStoryDto.getUserStoryText());
				// System.out.println(userStoryDto);

				BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
				PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(client.getOutputStream())), true);

				if (connectedSalahors != salahorPorts.size()) {
					int nextPort = getNextSalahorPort();
					out.println(nextPort);
					salahorPorts.put(nextPort, null);
				}

				String line = null;
				while ((line = in.readLine()) != null) {
					final String reportLine = line;
					Log.d("ServerActivity", line);

					if (messagesFromSalahors != null) {
						messagesFromSalahors += line;
					} else {
						messagesFromSalahors = line;
					}
					// add the connection to listening ports. First message from a salahor will be the port he is listening on.

					handler.post(new Runnable() {
						@Override
						public void run() {
							textView.setText(connectedSalahors >= 0 ? "Connected" : "No users connected yet");
							textMessages.setText(messagesFromSalahors);
						}
					});
				}
			} catch (Exception e) {
				handler.post(new Runnable() {
					@Override
					public void run() {
						textView.setText("Oops. Connection interrupted. Please reconnect your phones.");
					}
				});
				e.printStackTrace();
			}

		}

		private int getNextSalahorPort() {
			return 8082 + salahorPorts.size();
		}
	}

	@Override
	protected void onStop() {
		super.onStop();
		try {
			// make sure you close the socket upon exiting
			serverSocket.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public class ClientThread implements Runnable {

		private UserStoryDto userStoryDto;

		public ClientThread(UserStoryDto userStoryDto) {
			this.userStoryDto = userStoryDto;
		}

		public void run() {
			try {
				Iterator<Entry<Integer, Socket>> it = salahorPorts.entrySet().iterator();
				while (it.hasNext()) {
					Map.Entry<Integer, Socket> salahorDetails = it.next();

					if (salahorDetails.getValue() == null) {
						InetAddress serverAddr = InetAddress.getByName(salahorIpAddress);
						Log.d("ClientActivity", "SM: Connecting...");

						salahorDetails.setValue(new Socket(serverAddr, salahorDetails.getKey() + connectedSalahors));
					}

					// while (connected) {
					ObjectOutputStream oos = null;
					try {
						Log.d("ClientActivity", "SM: Sending command.");

						if (messagesFromSalahors != null) {
							savePreviousUS();
						}

						oos = new ObjectOutputStream(salahorDetails.getValue().getOutputStream());
						oos.writeObject(userStoryDto);
						messagesFromSalahors = null;

						Log.d("User Story DTO with user story ", userStoryDto.getUserStoryText() + " has bee successfully sent!");
						Log.d("ClientActivity", "SM: Sent.");
					} catch (Exception e) {
						Log.e("ClientActivity", "S: Error", e);
					}
				}
			} catch (Exception e) {
				Log.e("ClientActivity", "C: Error", e);
			}
		}

		private void savePreviousUS() {
			// TODO Auto-generated method stub

		}
	}

	private void registerItemListener() {
		final ListView lw = this.getListView();

		lw.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
				String userStory = usItems.get(arg2);
				if (userStory != null) {
					UserStoryDto userStoreyDto = new UserStoryDto(null, userStory, 0);
					Thread cThread = new Thread(new ClientThread(userStoreyDto));
					cThread.start();
				}
			}
		});
	}
}